/*
 * TransactionTests.java
 *
 *  
 */
package org.msb.finance.data;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Iterator;

import org.junit.Before;
import org.junit.Test;

/**
 * 
 * 
 * @author Marc Boudreau
 * 
 */
@SuppressWarnings("nls")
public class TransactionTests {

	/*
	 * 
	 */
	private Transaction transaction;

	/**
	 * @throws Exception
	 */
	@Before
	public void setUp() throws Exception {
		transaction = new Transaction();
	}

	/**
	 * Test method for {@link Transaction#getAmount()}.
	 */
	@Test
	public void testGetAmount() {
		assertEquals(new BigDecimal(0), transaction.getAmount());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testGetAmountWithDetails() throws Exception {
		final TransactionDetail td1 = new FakeTransactionDetail(3.5f);
		final TransactionDetail td2 = new FakeTransactionDetail(7.5f);
		final TransactionDetail td3 = new FakeTransactionDetail(22f);

		transaction.addTransactionDetail(td1);
		transaction.addTransactionDetail(td2);
		transaction.addTransactionDetail(td3);

		assertEquals(new BigDecimal(33f), transaction.getAmount());
	}

	/**
	 * Test method for {@link Transaction#setDate(Date)}.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testSetDate() throws Exception {
		final Date DATE = new Date();
		transaction.setDate(DATE);

		assertEquals(DATE, transaction.getDate());
	}

	/**
	 * Test method for {@link Transaction#setPayee(Payee)}.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testSetPayee() throws Exception {
		final Payee PAYEE = new Payee("Test Payee");
		transaction.setPayee(PAYEE);

		assertEquals(PAYEE, transaction.getPayee());
	}

	/**
	 * Test method for {@link Transaction#linkTransactions(Transaction, Transaction)}.
	 * 
	 * @throws Exception
	 */
	@Test
	public void testLinkTransactions() throws Exception {
		final Transaction t1 = new Transaction();

		Transaction.linkTransactions(transaction, t1);

		assertEquals(t1, transaction.getRelatedTransaction());
		assertEquals(transaction, t1.getRelatedTransaction());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testLinkTransactionsLinkedToOthers() throws Exception {
		final Transaction t1 = new Transaction();
		final Transaction t2 = new Transaction();
		final Transaction t3 = new Transaction();

		Transaction.linkTransactions(transaction, t2);
		Transaction.linkTransactions(t1, t3);

		Transaction.linkTransactions(transaction, t1);

		assertEquals(t1, transaction.getRelatedTransaction());
		assertEquals(transaction, t1.getRelatedTransaction());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testLinkTransactionsLinkToNull() throws Exception {
		Transaction.linkTransactions(transaction, null);

		assertNull(transaction.getRelatedTransaction());

		Transaction.linkTransactions(null, transaction);

		assertNull(transaction.getRelatedTransaction());
	}

	/**
	 * Test method for {@link Transaction#unlinkTransaction(Transaction)}.
	 */
	@Test
	public void testUnlinkTransaction() {
		final Transaction t1 = new Transaction();

		Transaction.linkTransactions(transaction, t1);
		Transaction.unlinkTransaction(transaction);

		assertNull(transaction.getRelatedTransaction());
		assertNull(t1.getRelatedTransaction());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testUnlinkTransactionCorrupted() throws Exception {
		final Transaction t1 = new Transaction();
		final Transaction t2 = new Transaction();

		Transaction.linkTransactions(t1, t2);
		transaction.setRelatedTransaction(t1);

		Transaction.unlinkTransaction(transaction);
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testUnlinkNullTransaction() throws Exception {
		Transaction.unlinkTransaction(null);
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testUnlinkTransactionNullRelated() throws Exception {
		Transaction.unlinkTransaction(transaction);
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testAddTransactionDetail() throws Exception {
		transaction.addTransactionDetail(new FakeTransactionDetail(0f));
		assertEquals(1, transaction.getTransactionDetailCount());

		transaction.addTransactionDetail(new FakeTransactionDetail(1f));
		assertEquals(2, transaction.getTransactionDetailCount());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testRemoveTransactionDetails() throws Exception {
		final TransactionDetail td1 = new FakeTransactionDetail(5f);
		final TransactionDetail td2 = new FakeTransactionDetail(10.4f);
		transaction.addTransactionDetail(td1);
		transaction.addTransactionDetail(td2);

		transaction.removeTransactionDetail(null);
		assertEquals(2, transaction.getTransactionDetailCount());

		transaction.removeTransactionDetail(td1);
		assertEquals(1, transaction.getTransactionDetailCount());

		transaction.removeTransactionDetail(td1);
		assertEquals(1, transaction.getTransactionDetailCount());

		transaction.removeTransactionDetail(td2);
		assertEquals(0, transaction.getTransactionDetailCount());
	}

	/**
	 * 
	 * @throws Exception
	 */
	@Test
	public void testGetTransactionDetails() throws Exception {
		final TransactionDetail td1 = new FakeTransactionDetail(5f);
		final TransactionDetail td2 = new FakeTransactionDetail(10.4f);
		transaction.addTransactionDetail(td1);
		transaction.addTransactionDetail(td2);

		Iterator<TransactionDetail> it = transaction.getTransactionDetails();
		assertTrue(it.hasNext());
	}

	/*
	 * 
	 */
	class FakeTransactionDetail extends TransactionDetail {

		/*
		 * 
		 */
		private float amount;

		/**
		 * 
		 * @param amount
		 */
		public FakeTransactionDetail(float amount) {
			this.amount = amount;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.msb.finance.data.TransactionDetail#getAmount()
		 */
		@Override
		public BigDecimal getAmount() {
			return new BigDecimal(amount);
		}

	}
}
